package com.hfb.mashibing.alip8.interview.deadlock;

/**
 * 问题描述：
 * 五个哲学家围着一张圆桌就餐，他们每个人面前都有一盘通心粉。由于通心粉很滑，所以需要两只筷子才能夹住，但每两个盘子之间只放着一只筷子。
 * 哲学家只有两个动作：要么就餐，要么思考。而且他们之间从不交谈。
 * 当一个哲学家饿了的时候，就拿起盘子左右两边的筷子开始就餐（不能同时拿起两只筷子）。就餐完以后，就把筷子放回盘子左右，继续思考。
 *
 * 注意：对java多线程不熟悉的可以先看下生产者－消费者模型是怎么实现的，然后再独立实现哲学家就餐问题．
 *
 * 解决方案２:
 *      给筷子编号，哲学家将要进餐时，要先从小号的开始拿．
 */

public class PhilosopherQuestion2 {
    // chopsticks
    private boolean[] used = new boolean[] { false, false, false, false, false };
    private static String LOCK = "lock";

    public static void main(String[] args) {
        PhilosopherQuestion2 philosopherQuestion = new PhilosopherQuestion2();
        philosopherQuestion.new Philosopher1(0).start();
        philosopherQuestion.new Philosopher1(1).start();
        philosopherQuestion.new Philosopher1(2).start();
        philosopherQuestion.new Philosopher1(3).start();
        philosopherQuestion.new Philosopher1(4).start();
    }


    class Philosopher1 extends Thread {
        private int num;

        public Philosopher1(int num) {
            this.num = num;
        }

        public void eating() {
            System.out.println("my num is " + num + " , I am eating...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void thinking() {
            System.out.println("my num is " + num + ", I am thinking...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        public void takeChopsticks() {
            synchronized (LOCK) {
                int min = Math.min(num, (num + 1) % 5);
                int max = Math.max(num, (num + 1) % 5);
                if (!used[min]) {//先尝试拿小号筷子，失败则进入等待状态，并释放锁
                    used[min] = true;
                    if(!used[max]) {//成功拿到小号筷子后，尝试拿大号筷子，失败，则进入等待状态，并释放锁，但是没有释放小号筷子
                        used[max] = true;
                    } else {
                        try {
                            LOCK.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                } else {
                    try {
                        LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        //放下筷子后，通知其他等待线程
        public void putDownChopsticks() {
            synchronized(LOCK) {
                used[num] = false;
                used[(num + 1) % 5] = false;
                System.out.println("my num is " + num + " , I have finished...");
                LOCK.notifyAll();
            }
        }

        @Override
        public void run() {
            while(true) {
                thinking();
                takeChopsticks();
                eating();
                putDownChopsticks();
            }
        }
    }

}
